# 什么是模块？
#
# 常见的场景：一个模块就是一个包含了python定义和声明的文件，文件名就是模块名字加上.py的后缀。
# 但其实import加载的模块分为四个通用类别：　
# 　　1 使用python编写的代码（.py文件）
# 　　2 已被编译为共享库或DLL的C或C++扩展
# 　　3 包好一组模块的包
# 　　4 使用C编写并链接到python解释器的内置模块
#
# 为何要使用模块？
# 如果你退出python解释器然后重新进入，那么你之前定义的函数或者变量都将丢失，因此我们通常将程序写到文件中以便永久保存下来，需要时就通过python test.py方式去执行，此时test.py被称为脚本script。
#
# 随着程序的发展，功能越来越多，为了方便管理，我们通常将程序分成一个个的文件，这样做程序的结构更清晰，方便管理。这时我们不仅仅可以把这些文件当做脚本去执行，还可以把他们当做模块来导入到其他的模块中，
# 实现了功能的重复利用，


# 模块可以包含可执行的语句和函数的定义，这些语句的目的是初始化模块，
# 它们只在模块名第一次遇到导入import语句时才执行
# （import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,
# 为了防止你重复导入，python的优化手段是：第一次导入后就将模块名加载到内存了，
# 后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用，
# 不会重新执行模块内的语句），如下


#import my_module as sm 为模块名起别名

# db_type = input('>>: ')
# if db_type == 'mysql':
#     import mysql as db
# elif db_type == 'oracle':
#     import oracle as db
# else:
#     import mysql as db
#
# db.sqlparse()

# import mysql
# data = 'test'
# print(data)
# print(mysql.data)

#在一行导入多个模块
#import sys,os,re

# 对比import my_module，会将源文件的名称空间'my_module'带到当前名称空间中，使用时必须是my_module.名字的方式
# 而from 语句相当于import，也会创建新的名称空间，但是将my_module中的名字直接导入到当前的名称空间中，在当前名称空间中，直接使用名字就可以了、
#如果当前有重名read1或者read2，那么会有覆盖效果。

#需要特别强调的一点是：python中的变量赋值不是一种存储操作，而只是一种绑定关系

# 也支持导入多行
# from my_module import (read1,
# read2,
# money)

#将模块作为脚本来执行
# calc.py
# def add(a, b):
#     return a + b
#
# if __name__ == '__main__':
#     print('test: 2 + 3 =', add(2, 3))

# $ python calc.py
# test: 2 + 3 = 5

# 注意： 代码中的 if 语句很有必要，这样既可以将模块作为独立的脚本运行，
# 又可以将其作为可导入的模块来使用__name__= 模块名

#模块搜索路径
import sys

# python解释器在启动时会自动加载一些模块，可以使用sys.modules查看
# print(sys.modules)

#所以总结模块的查找顺序是：内存中已经加载的模块->内置模块->sys.path路径中包含的模块

#包
#包是一种通过使用‘.模块名’来组织python模块名称空间的方式。

# １. 无论是import形式还是from...import形式，凡是在导入语句中（而不是在使用时）遇到带点的，都要第一时间提高警觉：这是关于包才有的导入语法
# 2. 包是目录级的（文件夹级），文件夹是用来组成py文件（包的本质就是一个包含__init__.py文件的目录）
# 3. import导入文件时，产生名称空间中的名字来源于文件，import 包，产生的名称空间的名字同样来源于文件，即包下的__init__.py，导入包本质就是在导入该文件
# 强调：
# 　　1. 在python3中，即使包下没有__init__.py文件，import 包仍然不会报错，而在python2中，包下一定要有该文件，否则import 包报错
# 　　2. 创建包的目的不是为了运行，而是被导入使用，记住，包只是模块的一种形式而已，包即模块

#包A和包B下有同名模块也不会冲突，如A.a与B.a来自俩个命名空间


# 2.1 注意事项
# 1.关于包相关的导入语句也分为import和from ... import ...两种，但是无论哪种，无论在什么位置，在导入时都必须遵循一个原则：凡是在导入时带点的，点的左边都必须是一个包，否则非法。可以带有一连串的点，如item.subitem.subsubitem,但都必须遵循这个原则。
# 2.对于导入后，在使用时就没有这种限制了，点的左边可以是包,模块，函数，类(它们都可以用点的方式调用自己的属性)。
# 3.对比import item 和from item import name的应用场景：
# 如果我们想直接使用name那必须使用后者。

#2.6 绝对导入和相对导入
#绝对导入
# from glance.cmd import manage
# manage.main()
#
# 相对导入
# from ..cmd import manage
# manage.main()

#特别需要注意的是：可以用import导入内置或者第三方模块（已经在sys.path中），但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中)，
# 应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式。

# import glance之后直接调用模块中的方法
# glance/

# ├── __init__.py     from .api import *
# from .cmd import *
# from .db import *
# ├── api
#
# │   ├── __init__.py   __all__ = ['policy','versions']
#
# │   ├── policy.py
#
# │   └── versions.py
#
# ├── cmd               __all__ = ['manage']
#
# │   ├── __init__.py
#
# │   └── manage.py
#
# └── db                __all__ = ['models']
#
# ├── __init__.py
#
# └── models.py
#
#
# import glance
# policy.get()